package audio;

import java.util.ArrayList;

import main.Contexto;

public class GerenteAudio implements Runnable, AudioListener 
{
	private static final long serialVersionUID = 1L;

	static private GerenteAudio instancia = null;

	private AudioWave tocadorWave;
	private AudioNormalizado tocadorGeral;
	private AudioSintetizado sintetizador;
	
	protected boolean avisaFimAudio;
	
	private AudioBase audioAtual;
	
	private ArrayList<AudioListener> listeners;
	
	private GerenteAudio()
	{
		Contexto contexto = Contexto.instancia();

		listeners = new ArrayList<AudioListener>();
		
		avisaFimAudio = false;
		
		tocadorWave = AudioWave.instancia();
		tocadorGeral = AudioNormalizado.instancia();
		sintetizador = AudioSintetizado.instancia();

		try 
		{
			sintetizador.iniciarSintetizador( contexto.getSistema() == Contexto.SISTEMA_WINDOWS );
		}
		catch ( Exception e ) 
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		tocadorWave.addAudioListener(this);
		tocadorGeral.addAudioListener(this);
		sintetizador.addAudioListener(this);
		
		audioAtual = null;
		AudioBase.setEstado( AudioBase.PARADO );
	}
	
	static public GerenteAudio instancia()
	{
		if ( instancia == null )
		{
			instancia = new GerenteAudio();
			new Thread(instancia).start();
			System.out.println("Criei Thread... ");
		}
		
		return instancia;
	}
	
	public void abortaAudio()
	{
		if ( audioAtual != null )
		{
			audioAtual.abortar();
			avisaFimAudio = false;
		}
	}

	public void falaSintetizada( String str )
	{
		System.out.println("Fala Sintetizada... " + str);
		abortaAudio();
		
		synchronized(sintetizador) 
		{
			audioAtual = sintetizador;
			sintetizador.escreve(str);
			System.out.println( audioAtual.getWhoIAm() + " ### Estado " + 
					AudioBase.getEstado());
		}
	}
	
	public void tocarWave( String nomeArq )
	{
		System.out.println("Tocar Wave... " + nomeArq);
		abortaAudio();

		synchronized(tocadorWave) 
		{
			audioAtual = tocadorWave;
			tocadorWave.tocar(nomeArq);
			System.out.println( audioAtual.getWhoIAm() + " ### Estado " + 
					AudioBase.getEstado());
		}
	}

	public void tocarAudio( String str )
	{
		System.out.println("Tocar Audio... " + str);
		abortaAudio();
		avisaFimAudio = true;

		synchronized(sintetizador) 
		{
			audioAtual = sintetizador;
			sintetizador.escreve(str);
			System.out.println( audioAtual.getWhoIAm() + " ### Estado " + 
					AudioBase.getEstado());
		}
	}
	
	public void tocarAudio( String nomeArq, float inicio, float fim )
	{
		System.out.println("Tocar Audio Arquivo... " + nomeArq);

		abortaAudio();
		avisaFimAudio = true;

		synchronized(tocadorGeral) 
		{
			audioAtual = tocadorGeral;
			tocadorGeral.tocar(nomeArq, inicio, fim);
			System.out.println( audioAtual.getWhoIAm() + " ### Estado " + 
					AudioBase.getEstado());
		}
	}
	
	public void encerrarAudio()
	{
		System.out.println( audioAtual.getWhoIAm() + " Encerrar. " ); 
		try 
		{
			tocadorWave.encerrar();
			tocadorGeral.encerrar();
			sintetizador.encerrar();
		}
		catch (AudioException e) 
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/*
	 * Manipulação do Evento SoundEvent
	 */
	
	//	Registra novo ouvinte para o evento SoundEvent	
	public void addAudioListener(AudioListener listener) 
	{
		listeners.add(listener);
	}
    
	//	Cancela registro de ouvinte para o evento SoundEvent	
	public void removeAudioListener(AudioListener listener) 
	{
		while (listeners.remove(listener))
			;
	}
	
	//	Obtem todos os ouvintes para o evento SoundEvent	
	public AudioListener[] getAudioListeners()
	{
		return listeners.toArray(new AudioListener[listeners.size()]);
	}
	
	@Override
	public void ErroAudio(AudioEvent e) 
	{
		if ( avisaFimAudio )
		{
			for (AudioListener listener : listeners) 
			{
				if ( e.isError() )
					listener.ErroAudio(e);
			}
		}
		else
			System.out.println(e.getMsgErro());
	}

	@Override
	public void FimDeFala(AudioEvent e) 
	{
		if ( audioAtual != null )
			System.out.println( audioAtual.getWhoIAm() + " - FIM DE FALA " + avisaFimAudio );

		if ( avisaFimAudio )
		{
			for (AudioListener listener : listeners) 
			{
				if ( e.isSilence() )
					listener.FimDeFala(e);
			}
		}
	}

	@Override
	public void run() 
	{
		int estadoAnterior = -1;
		
		while ( true ) 
		{
			if ( audioAtual != null )
			{
				if ( estadoAnterior != AudioBase.getEstado() )
				{
					System.out.println( audioAtual.getWhoIAm() + " - Estado " + 
							AudioBase.getEstado());
					estadoAnterior = AudioBase.getEstado();
				}
			}

			try 
			{
				switch ( AudioBase.getEstado() )
				{
				case AudioBase.INICIAR:
					audioAtual.estadoIniciar();
					break;
				case AudioBase.TOCAR:
					audioAtual.estadoTocar();
					break;
				case AudioBase.TESTAR:
					audioAtual.estadoTestar();
					break;
				case AudioBase.ENCERRAR:
					return;    // Saio da Thread
				}
			}
			catch (AudioException e) 
			{
				audioAtual.mandaEventoErro( e.getMessage() );
			}
		}
	}
}
